1   /*
2    * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.java.util.jar.pack;
27  
28  import java.io.IOException;
29  import java.util.Arrays;
30  import static com.sun.java.util.jar.pack.Constants.*;
31  
32  /**
33   * A parsed bytecode instruction.
34   * Provides accessors to various relevant bits.
35   * @author John Rose
36   */
37  class Instruction  {
38      protected byte[] bytes;  // bytecodes
39      protected int pc;        // location of this instruction
40      protected int bc;        // opcode of this instruction
41      protected int w;         // 0 if normal, 1 if a _wide prefix at pc
42      protected int length;    // bytes in this instruction
43  
44      protected boolean special;
45  
46      protected Instruction(byte[] bytes, int pc, int bc, int w, int length) {
47          reset(bytes, pc, bc, w, length);
48      }
49      private void reset(byte[] bytes, int pc, int bc, int w, int length) {
50          this.bytes = bytes;
51          this.pc = pc;
52          this.bc = bc;
53          this.w = w;
54          this.length = length;
55      }
56  
57      public int getBC() {
58          return bc;
59      }
60      public boolean isWide() {
61          return w != 0;
62      }
63      public byte[] getBytes() {
64          return bytes;
65      }
66      public int getPC() {
67          return pc;
68      }
69      public int getLength() {
70          return length;
71      }
72      public int getNextPC() {
73          return pc + length;
74      }
75  
76      public Instruction next() {
77          int npc = pc + length;
78          if (npc == bytes.length)
79              return null;
80          else
81              return Instruction.at(bytes, npc, this);
82      }
83  
84      public boolean isNonstandard() {
85          return isNonstandard(bc);
86      }
87  
88      public void setNonstandardLength(int length) {
89          assert(isNonstandard());
90          this.length = length;
91      }
92  
93  
94      /** A fake instruction at this pc whose next() will be at nextpc. */
95      public Instruction forceNextPC(int nextpc) {
96          int llength = nextpc - pc;
97          return new Instruction(bytes, pc, -1, -1, llength);
98      }
99  
100     public static Instruction at(byte[] bytes, int pc) {
101         return Instruction.at(bytes, pc, null);
102     }
103 
104     public static Instruction at(byte[] bytes, int pc, Instruction reuse) {
105         int bc = getByte(bytes, pc);
106         int prefix = -1;
107         int w = 0;
108         int length = BC_LENGTH[w][bc];
109         if (length == 0) {
110             // Hard cases:
111             switch (bc) {
112             case _wide:
113                 bc = getByte(bytes, pc+1);
114                 w = 1;
115                 length = BC_LENGTH[w][bc];
116                 if (length == 0) {
117                     // unknown instruction; treat as one byte
118                     length = 1;
119                 }
120                 break;
121             case _tableswitch:
122                 return new TableSwitch(bytes, pc);
123             case _lookupswitch:
124                 return new LookupSwitch(bytes, pc);
125             default:
126                 // unknown instruction; treat as one byte
127                 length = 1;
128                 break;
129             }
130         }
131         assert(length > 0);
132         assert(pc+length <= bytes.length);
133         // Speed hack:  Instruction.next reuses self if possible.
134         if (reuse != null && !reuse.special) {
135             reuse.reset(bytes, pc, bc, w, length);
136             return reuse;
137         }
138         return new Instruction(bytes, pc, bc, w, length);
139     }
140 
141     // Return the constant pool reference type, or 0 if none.
142     public byte getCPTag() {
143         return BC_TAG[w][bc];
144     }
145 
146     // Return the constant pool index, or -1 if none.
147     public int getCPIndex() {
148         int indexLoc = BC_INDEX[w][bc];
149         if (indexLoc == 0)  return -1;
150         assert(w == 0);
151         if (length == 2)
152             return getByte(bytes, pc+indexLoc);  // _ldc opcode only
153         else
154             return getShort(bytes, pc+indexLoc);
155     }
156 
157     public void setCPIndex(int cpi) {
158         int indexLoc = BC_INDEX[w][bc];
159         assert(indexLoc != 0);
160         if (length == 2)
161             setByte(bytes, pc+indexLoc, cpi);  // _ldc opcode only
162         else
163             setShort(bytes, pc+indexLoc, cpi);
164         assert(getCPIndex() == cpi);
165     }
166 
167     public ConstantPool.Entry getCPRef(ConstantPool.Entry[] cpMap) {
168         int index = getCPIndex();
169         return (index < 0) ? null : cpMap[index];
170     }
171 
172     // Return the slot of the affected local, or -1 if none.
173     public int getLocalSlot() {
174         int slotLoc = BC_SLOT[w][bc];
175         if (slotLoc == 0)  return -1;
176         if (w == 0)
177             return getByte(bytes, pc+slotLoc);
178         else
179             return getShort(bytes, pc+slotLoc);
180     }
181 
182     // Return the target of the branch, or -1 if none.
183     public int getBranchLabel() {
184         int branchLoc = BC_BRANCH[w][bc];
185         if (branchLoc == 0)  return -1;
186         assert(w == 0);
187         assert(length == 3 || length == 5);
188         int offset;
189         if (length == 3)
190             offset = (short)getShort(bytes, pc+branchLoc);
191         else
192             offset = getInt(bytes, pc+branchLoc);
193         assert(offset+pc >= 0);
194         assert(offset+pc <= bytes.length);
195         return offset+pc;
196     }
197 
198     public void setBranchLabel(int targetPC) {
199         int branchLoc = BC_BRANCH[w][bc];
200         assert(branchLoc != 0);
201         if (length == 3)
202             setShort(bytes, pc+branchLoc, targetPC-pc);
203         else
204             setInt(bytes, pc+branchLoc, targetPC-pc);
205         assert(targetPC == getBranchLabel());
206     }
207 
208     // Return the trailing constant in the instruction (as a signed value).
209     // Return 0 if there is none.
210     public int getConstant() {
211         int conLoc = BC_CON[w][bc];
212         if (conLoc == 0)  return 0;
213         switch (length - conLoc) {
214         case 1: return (byte) getByte(bytes, pc+conLoc);
215         case 2: return (short) getShort(bytes, pc+conLoc);
216         }
217         assert(false);
218         return 0;
219     }
220 
221     public void setConstant(int con) {
222         int conLoc = BC_CON[w][bc];
223         assert(conLoc != 0);
224         switch (length - conLoc) {
225         case 1: setByte(bytes, pc+conLoc, con); break;
226         case 2: setShort(bytes, pc+conLoc, con); break;
227         }
228         assert(con == getConstant());
229     }
230 
231     public abstract static class Switch extends Instruction {
232         // Each case is a (value, label) pair, indexed 0 <= n < caseCount
233         public abstract int  getCaseCount();
234         public abstract int  getCaseValue(int n);
235         public abstract int  getCaseLabel(int n);
236         public abstract void setCaseCount(int caseCount);
237         public abstract void setCaseValue(int n, int value);
238         public abstract void setCaseLabel(int n, int targetPC);
239         protected abstract int getLength(int caseCount);
240 
241         public int  getDefaultLabel()             { return intAt(0)+pc; }
242         public void setDefaultLabel(int targetPC) { setIntAt(0, targetPC-pc); }
243 
244         protected int apc;        // aligned pc (table base)
245         protected int intAt(int n) { return getInt(bytes, apc + n*4); }
246         protected void setIntAt(int n, int x) { setInt(bytes, apc + n*4, x); }
247         protected Switch(byte[] bytes, int pc, int bc) {
248             super(bytes, pc, bc, /*w*/0, /*length*/0);
249             this.apc = alignPC(pc+1);
250             this.special = true;
251             length = getLength(getCaseCount());
252         }
253         public int getAlignedPC() { return apc; }
254         public String toString() {
255             String s = super.toString();
256             s += " Default:"+labstr(getDefaultLabel());
257             int caseCount = getCaseCount();
258             for (int i = 0; i < caseCount; i++) {
259                 s += "\n\tCase "+getCaseValue(i)+":"+labstr(getCaseLabel(i));
260             }
261             return s;
262         }
263         public static int alignPC(int apc) {
264             while (apc % 4 != 0)  ++apc;
265             return apc;
266         }
267     }
268 
269     public static class TableSwitch extends Switch {
270         // apc:  (df, lo, hi, (hi-lo+1)*(label))
271         public int getLowCase()        { return intAt(1); }
272         public int getHighCase()       { return intAt(2); }
273         public int getCaseCount()      { return intAt(2)-intAt(1)+1; }
274         public int getCaseValue(int n) { return getLowCase()+n; }
275         public int getCaseLabel(int n) { return intAt(3+n)+pc; }
276 
277         public void setLowCase(int val)  { setIntAt(1, val); }
278         public void setHighCase(int val) { setIntAt(2, val); }
279         public void setCaseLabel(int n, int tpc) { setIntAt(3+n, tpc-pc); }
280         public void setCaseCount(int caseCount) {
281             setHighCase(getLowCase() + caseCount - 1);
282             length = getLength(caseCount);
283         }
284         public void setCaseValue(int n, int val) {
285             if (n != 0)  throw new UnsupportedOperationException();
286             int caseCount = getCaseCount();
287             setLowCase(val);
288             setCaseCount(caseCount);  // keep invariant
289         }
290 
291         TableSwitch(byte[] bytes, int pc) {
292             super(bytes, pc, _tableswitch);
293         }
294         protected int getLength(int caseCount) {
295             return (apc-pc) + (3 + caseCount) * 4;
296         }
297     }
298 
299     public static class LookupSwitch extends Switch {
300         // apc:  (df, nc, nc*(case, label))
301         public int getCaseCount()      { return intAt(1); }
302         public int getCaseValue(int n) { return intAt(2+n*2+0); }
303         public int getCaseLabel(int n) { return intAt(2+n*2+1)+pc; }
304 
305         public void setCaseCount(int caseCount)  {
306             setIntAt(1, caseCount);
307             length = getLength(caseCount);
308         }
309         public void setCaseValue(int n, int val) { setIntAt(2+n*2+0, val); }
310         public void setCaseLabel(int n, int tpc) { setIntAt(2+n*2+1, tpc-pc); }
311 
312         LookupSwitch(byte[] bytes, int pc) {
313             super(bytes, pc, _lookupswitch);
314         }
315         protected int getLength(int caseCount) {
316             return (apc-pc) + (2 + caseCount*2) * 4;
317         }
318     }
319 
320     /** Two instructions are equal if they have the same bytes. */
321     public boolean equals(Object o) {
322         return (o != null) && (o.getClass() == Instruction.class)
323                 && equals((Instruction) o);
324     }
325 
326     public int hashCode() {
327         int hash = 3;
328         hash = 11 * hash + Arrays.hashCode(this.bytes);
329         hash = 11 * hash + this.pc;
330         hash = 11 * hash + this.bc;
331         hash = 11 * hash + this.w;
332         hash = 11 * hash + this.length;
333         return hash;
334     }
335 
336     public boolean equals(Instruction that) {
337         if (this.pc != that.pc)            return false;
338         if (this.bc != that.bc)            return false;
339         if (this.w  != that.w)             return false;
340         if (this.length  != that.length)   return false;
341         for (int i = 1; i < length; i++) {
342             if (this.bytes[this.pc+i] != that.bytes[that.pc+i])
343                 return false;
344         }
345         return true;
346     }
347 
348     static String labstr(int pc) {
349         if (pc >= 0 && pc < 100000)
350             return ((100000+pc)+"").substring(1);
351         return pc+"";
352     }
353     public String toString() {
354         return toString(null);
355     }
356     public String toString(ConstantPool.Entry[] cpMap) {
357         String s = labstr(pc) + ": ";
358         if (bc >= _bytecode_limit) {
359             s += Integer.toHexString(bc);
360             return s;
361         }
362         if (w == 1)  s += "wide ";
363         String bcname = (bc < BC_NAME.length)? BC_NAME[bc]: null;
364         if (bcname == null) {
365             return s+"opcode#"+bc;
366         }
367         s += bcname;
368         int tag = getCPTag();
369         if (tag != 0)  s += " "+ConstantPool.tagName(tag)+":";
370         int idx = getCPIndex();
371         if (idx >= 0)  s += (cpMap == null) ? ""+idx : "="+cpMap[idx].stringValue();
372         int slt = getLocalSlot();
373         if (slt >= 0)  s += " Local:"+slt;
374         int lab = getBranchLabel();
375         if (lab >= 0)  s += " To:"+labstr(lab);
376         int con = getConstant();
377         if (con != 0)  s += " Con:"+con;
378         return s;
379     }
380 
381 
382     //public static byte constantPoolTagFor(int bc) { return BC_TAG[0][bc]; }
383 
384     /// Fetching values from byte arrays:
385 
386     public int getIntAt(int off) {
387         return getInt(bytes, pc+off);
388     }
389     public int getShortAt(int off) {
390         return getShort(bytes, pc+off);
391     }
392     public int getByteAt(int off) {
393         return getByte(bytes, pc+off);
394     }
395 
396 
397     public static int getInt(byte[] bytes, int pc) {
398         return (getShort(bytes, pc+0) << 16) + (getShort(bytes, pc+2) << 0);
399     }
400     public static int getShort(byte[] bytes, int pc) {
401         return (getByte(bytes, pc+0) << 8) + (getByte(bytes, pc+1) << 0);
402     }
403     public static int getByte(byte[] bytes, int pc) {
404         return bytes[pc] & 0xFF;
405     }
406 
407 
408     public static void setInt(byte[] bytes, int pc, int x) {
409         setShort(bytes, pc+0, x >> 16);
410         setShort(bytes, pc+2, x >> 0);
411     }
412     public static void setShort(byte[] bytes, int pc, int x) {
413         setByte(bytes, pc+0, x >> 8);
414         setByte(bytes, pc+1, x >> 0);
415     }
416     public static void setByte(byte[] bytes, int pc, int x) {
417         bytes[pc] = (byte)x;
418     }
419 
420     // some bytecode classifiers
421 
422 
423     public static boolean isNonstandard(int bc) {
424         return BC_LENGTH[0][bc] < 0;
425     }
426 
427     public static int opLength(int bc) {
428         int l = BC_LENGTH[0][bc];
429         assert(l > 0);
430         return l;
431     }
432     public static int opWideLength(int bc) {
433         int l = BC_LENGTH[1][bc];
434         assert(l > 0);
435         return l;
436     }
437 
438     public static boolean isLocalSlotOp(int bc) {
439         return (bc < BC_SLOT[0].length && BC_SLOT[0][bc] > 0);
440     }
441 
442     public static boolean isBranchOp(int bc) {
443         return (bc < BC_BRANCH[0].length && BC_BRANCH[0][bc] > 0);
444     }
445 
446     public static boolean isCPRefOp(int bc) {
447         if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0)  return true;
448         if (bc >= _xldc_op && bc < _xldc_limit)  return true;
449         return false;
450     }
451 
452     public static byte getCPRefOpTag(int bc) {
453         if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0)  return BC_TAG[0][bc];
454         if (bc >= _xldc_op && bc < _xldc_limit)  return CONSTANT_Literal;
455         return CONSTANT_None;
456     }
457 
458     public static boolean isFieldOp(int bc) {
459         return (bc >= _getstatic && bc <= _putfield);
460     }
461 
462     public static boolean isInvokeInitOp(int bc) {
463         return (bc >= _invokeinit_op && bc < _invokeinit_limit);
464     }
465 
466     public static boolean isSelfLinkerOp(int bc) {
467         return (bc >= _self_linker_op && bc < _self_linker_limit);
468     }
469 
470     /// Format definitions.
471 
472     static private final byte[][] BC_LENGTH  = new byte[2][0x100];
473     static private final byte[][] BC_INDEX   = new byte[2][0x100];
474     static private final byte[][] BC_TAG     = new byte[2][0x100];
475     static private final byte[][] BC_BRANCH  = new byte[2][0x100];
476     static private final byte[][] BC_SLOT    = new byte[2][0x100];
477     static private final byte[][] BC_CON     = new byte[2][0x100];
478     static private final String[] BC_NAME    = new String[0x100]; // debug only
479     static private final String[][] BC_FORMAT  = new String[2][_bytecode_limit]; // debug only
480     static {
481         for (int i = 0; i < _bytecode_limit; i++) {
482             BC_LENGTH[0][i] = -1;
483             BC_LENGTH[1][i] = -1;
484         }
485         def("b", _nop, _dconst_1);
486         def("bx", _bipush);
487         def("bxx", _sipush);
488         def("bk", _ldc);                                // do not pack
489         def("bkk", _ldc_w, _ldc2_w);            // do not pack
490         def("blwbll", _iload, _aload);
491         def("b", _iload_0, _saload);
492         def("blwbll", _istore, _astore);
493         def("b", _istore_0, _lxor);
494         def("blxwbllxx", _iinc);
495         def("b", _i2l, _dcmpg);
496         def("boo", _ifeq, _jsr);                        // pack oo
497         def("blwbll", _ret);
498         def("", _tableswitch, _lookupswitch);   // pack all ints, omit padding
499         def("b", _ireturn, _return);
500         def("bkf", _getstatic, _putfield);              // pack kf (base=Field)
501         def("bkm", _invokevirtual, _invokestatic);      // pack kn (base=Method)
502         def("bkixx", _invokeinterface);         // pack ki (base=IMethod), omit xx
503         def("", _xxxunusedxxx);
504         def("bkc", _new);                               // pack kc
505         def("bx", _newarray);
506         def("bkc", _anewarray);                 // pack kc
507         def("b", _arraylength, _athrow);
508         def("bkc", _checkcast, _instanceof);    // pack kc
509         def("b", _monitorenter, _monitorexit);
510         def("", _wide);
511         def("bkcx", _multianewarray);           // pack kc
512         def("boo", _ifnull, _ifnonnull);                // pack oo
513         def("boooo", _goto_w, _jsr_w);          // pack oooo
514         for (int i = 0; i < _bytecode_limit; i++) {
515             //System.out.println(i+": l="+BC_LENGTH[0][i]+" i="+BC_INDEX[0][i]);
516             //assert(BC_LENGTH[0][i] != -1);
517             if (BC_LENGTH[0][i] == -1) {
518                 assert(i == _xxxunusedxxx);
519                 continue;  // unknown opcode
520             }
521 
522             // Have a complete mapping, to support spurious _wide prefixes.
523             if (BC_LENGTH[1][i] == -1)
524                 BC_LENGTH[1][i] = (byte)(1+BC_LENGTH[0][i]);
525         }
526 
527         String names =
528   "nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 "+
529   "iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 "+
530   "bipush sipush ldc ldc_w ldc2_w iload lload fload dload aload iload_0 "+
531   "iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 "+
532   "fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 "+
533   "aload_3 iaload laload faload daload aaload baload caload saload istore "+
534   "lstore fstore dstore astore istore_0 istore_1 istore_2 istore_3 lstore_0 "+
535   "lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 "+
536   "dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore "+
537   "lastore fastore dastore aastore bastore castore sastore pop pop2 dup "+
538   "dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd isub lsub "+
539   "fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem "+
540   "ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior lor "+
541   "ixor lxor iinc i2l i2f i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f i2b i2c "+
542   "i2s lcmp fcmpl fcmpg dcmpl dcmpg ifeq ifne iflt ifge ifgt ifle if_icmpeq "+
543   "if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "+
544   "goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "+
545   "areturn return getstatic putstatic getfield putfield invokevirtual "+
546   "invokespecial invokestatic invokeinterface xxxunusedxxx new newarray "+
547   "anewarray arraylength athrow checkcast instanceof monitorenter "+
548   "monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w ";
549         for (int bc = 0; names.length() > 0; bc++) {
550             int sp = names.indexOf(' ');
551             BC_NAME[bc] = names.substring(0, sp);
552             names = names.substring(sp+1);
553         }
554     }
555     public static String byteName(int bc) {
556         String iname;
557         if (bc < BC_NAME.length && BC_NAME[bc] != null) {
558             iname = BC_NAME[bc];
559         } else if (isSelfLinkerOp(bc)) {
560             int idx = (bc - _self_linker_op);
561             boolean isSuper = (idx >= _self_linker_super_flag);
562             if (isSuper)  idx -= _self_linker_super_flag;
563             boolean isAload = (idx >= _self_linker_aload_flag);
564             if (isAload)  idx -= _self_linker_aload_flag;
565             int origBC = _first_linker_op + idx;
566             assert(origBC >= _first_linker_op && origBC <= _last_linker_op);
567             iname = BC_NAME[origBC];
568             iname += (isSuper ? "_super" : "_this");
569             if (isAload)  iname = "aload_0&" + iname;
570             iname = "*"+iname;
571         } else if (isInvokeInitOp(bc)) {
572             int idx = (bc - _invokeinit_op);
573             switch (idx) {
574             case _invokeinit_self_option:
575                 iname = "*invokespecial_init_this"; break;
576             case _invokeinit_super_option:
577                 iname = "*invokespecial_init_super"; break;
578             default:
579                 assert(idx == _invokeinit_new_option);
580                 iname = "*invokespecial_init_new"; break;
581             }
582         } else {
583             switch (bc) {
584             case _ildc:  iname = "*ildc"; break;
585             case _fldc:  iname = "*fldc"; break;
586             case _ildc_w:  iname = "*ildc_w"; break;
587             case _fldc_w:  iname = "*fldc_w"; break;
588             case _dldc2_w:  iname = "*dldc2_w"; break;
589             case _cldc:  iname = "*cldc"; break;
590             case _cldc_w:  iname = "*cldc_w"; break;
591             case _byte_escape:  iname = "*byte_escape"; break;
592             case _ref_escape:  iname = "*ref_escape"; break;
593             case _end_marker:  iname = "*end"; break;
594             default:  iname = "*bc#"+bc; break;
595             }
596         }
597         return iname;
598     }
599     private static int BW = 4;  // width of classification field
600     private static void def(String fmt, int bc) {
601         def(fmt, bc, bc);
602     }
603     private static void def(String fmt, int from_bc, int to_bc) {
604         String[] fmts = { fmt, null };
605         if (fmt.indexOf('w') > 0) {
606             fmts[1] = fmt.substring(fmt.indexOf('w'));
607             fmts[0] = fmt.substring(0, fmt.indexOf('w'));
608         }
609         for (int w = 0; w <= 1; w++) {
610             fmt = fmts[w];
611             if (fmt == null)  continue;
612             int length = fmt.length();
613             int index  = Math.max(0, fmt.indexOf('k'));
614             int tag    = CONSTANT_None;
615             int branch = Math.max(0, fmt.indexOf('o'));
616             int slot   = Math.max(0, fmt.indexOf('l'));
617             int con    = Math.max(0, fmt.indexOf('x'));
618             if (index > 0 && index+1 < length) {
619                 switch (fmt.charAt(index+1)) {
620                     case 'c': tag = CONSTANT_Class; break;
621                     case 'k': tag = CONSTANT_Literal; break;
622                     case 'f': tag = CONSTANT_Fieldref; break;
623                     case 'm': tag = CONSTANT_Methodref; break;
624                     case 'i': tag = CONSTANT_InterfaceMethodref; break;
625                 }
626                 assert(tag != CONSTANT_None);
627             } else if (index > 0 && length == 2) {
628                 assert(from_bc == _ldc);
629                 tag = CONSTANT_Literal;  // _ldc opcode only
630             }
631             for (int bc = from_bc; bc <= to_bc; bc++) {
632                 BC_FORMAT[w][bc] = fmt;
633                 assert(BC_LENGTH[w][bc] == -1);
634                 BC_LENGTH[w][bc] = (byte) length;
635                 BC_INDEX[w][bc]  = (byte) index;
636                 BC_TAG[w][bc]    = (byte) tag;
637                 assert(!(index == 0 && tag != CONSTANT_None));
638                 BC_BRANCH[w][bc] = (byte) branch;
639                 BC_SLOT[w][bc]   = (byte) slot;
640                 assert(branch == 0 || slot == 0);   // not both branch & local
641                 assert(branch == 0 || index == 0);  // not both branch & cp
642                 assert(slot == 0   || index == 0);  // not both local & cp
643                 BC_CON[w][bc]    = (byte) con;
644             }
645         }
646     }
647 
648     public static void opcodeChecker(byte[] code) throws FormatException {
649         Instruction i = at(code, 0);
650         while (i != null) {
651             int opcode = i.getBC();
652             if (opcode == _xxxunusedxxx || opcode < _nop || opcode > _jsr_w) {
653                 String message = "illegal opcode: " + opcode + " " + i;
654                 throw new FormatException(message);
655             }
656             i = i.next();
657         }
658     }
659     static class FormatException extends IOException {
660         FormatException(String message) {
661             super(message);
662         }
663     }
664 }